home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / b / b.lha / B / src / bed / scrn.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-11-24  |  9.7 KB  |  481 lines

  1. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
  2. static char rcsid[] = "$Header: scrn.c,v 2.5 85/08/22 16:07:10 timo Exp $";
  3.  
  4. /*
  5.  * B editor -- Screen management package, higher level routines.
  6.  */
  7.  
  8. #include "b.h"
  9. #include "erro.h"
  10. #include "bobj.h"
  11. #include "node.h"
  12. #include "supr.h"
  13. #include "gram.h"
  14. #include "cell.h"
  15.  
  16.  
  17. extern bool dflag;
  18.  
  19. cell *gettop();
  20. extern int focy;
  21. extern int focx;
  22.  
  23. Visible int winstart;
  24.  
  25. Visible int winheight;
  26. Visible int indent;
  27. Visible int llength;
  28.  
  29. Visible bool noscroll;
  30. Visible bool nosense;
  31.  
  32. Hidden cell *tops;
  33.  
  34.  
  35. /*
  36.  * Actual screen update.
  37.  */
  38.  
  39. Visible Procedure
  40. actupdate(copybuffer, recording, lasttime)
  41.     value copybuffer;
  42.     bool recording;
  43.     bool lasttime; /* Yes if called from final screen update */
  44. {
  45.     register cell *p;
  46.     cell *top = tops;
  47.     register int diff;
  48.     register int curlno;
  49.     register int delcnt = 0; /* Lines deleted during the process. */
  50.         /* Used as offset for lines that are on the screen. */
  51.     int totlines = 0;
  52.     int topline = 0;
  53.     int scrlines = 0;
  54.  
  55.     if (winstart > 0)
  56.         growwin();
  57.     if (winstart <= 0) {
  58.         top = gettop(tops);
  59.         for (p = tops; p && p != top; p = p->c_link)
  60.             ++topline;
  61.         totlines = topline;
  62.     }
  63.     startactupdate(lasttime);
  64.     focy = Nowhere;
  65.     for (p = top, curlno = winstart; p && curlno < winheight;
  66.         curlno += Space(p), p = p->c_link) {
  67.         ++scrlines;
  68.         if (lasttime) {
  69.             p->c_newfocus = No;
  70.             p->c_newvhole = 0;
  71.         }
  72.         if (p->c_onscreen != Nowhere && Space(p) == Oldspace(p)) {
  73.             /* Old comrade */
  74.             diff = p->c_onscreen - (curlno+delcnt);
  75.             /* diff can't be negative due to 'makeroom' below! */
  76.             if (diff > 0) { /* Get him here */
  77.                 trmscrollup(curlno, winheight, diff);
  78.                 delcnt += diff;
  79.             }
  80.             if (p->c_oldfocus || p->c_newfocus
  81.                 || p->c_oldindent != p->c_newindent
  82.                 || p->c_onscreen + Space(p) >= winheight) {
  83.                 delcnt = make2room(p, curlno, delcnt);
  84.                 outline(p, curlno);
  85.             }
  86.         }
  87.         else { /* New guy, make him toe the line */
  88.             delcnt = makeroom(p, curlno, delcnt);
  89.             delcnt = make2room(p, curlno, delcnt);
  90.             outline(p, curlno);
  91.         }
  92.         p->c_onscreen = curlno;
  93.         p->c_oldindent = p->c_newindent;
  94.         p->c_oldvhole = p->c_newvhole;
  95.         p->c_oldfocus = p->c_newfocus;
  96.     }
  97.     totlines += scrlines;
  98.     for (; p; p = p->c_link) { /* Count rest and remove old memories */
  99.         ++totlines;
  100.         /* This code should never find any garbage?! */
  101. #ifndef NDEBUG
  102.         if (p->c_onscreen != Nowhere)
  103.             debug("[Garbage removed from screen list]");
  104. #endif NDEBUG
  105.         p->c_onscreen = Nowhere;
  106.     }
  107.     trmscrollup(curlno, winheight, -delcnt);
  108.     curlno += delcnt;
  109.     if (curlno < winheight) { /* Clear lines beyond end of unit */
  110.         trmputdata(curlno, winheight-1, 0, "");
  111.         scrlines += winheight-curlno;
  112.     }
  113.     if (!lasttime) {
  114.         stsline(totlines, topline, scrlines, copybuffer, recording);
  115.         if (focy != Nowhere)
  116.             trmsync(focy, focx);
  117.         else
  118.             trmsync(winheight, 0);
  119.     }
  120.     endactupdate();
  121. }
  122.  
  123.  
  124. /*
  125.  * Grow the window if not maximum size.
  126.  */
  127.  
  128. Hidden Procedure
  129. growwin()
  130. {
  131.     register int winsize;
  132.     register int growth;
  133.     register cell *p;
  134.  
  135.     winsize = 0;
  136.     for (p = tops; p; p = p->c_link)
  137.         winsize += Space(p);
  138.     if (winsize <= winheight - winstart)
  139.         return; /* No need to grow */
  140.     if (winsize > winheight)
  141.         winsize = winheight; /* Limit size to maximum available */
  142.  
  143.     growth = winsize - (winheight - winstart);
  144.     trmscrollup(0, winheight - (winstart!=winheight), growth);
  145.     winstart -= growth;
  146.     for (p = tops; p; p = p->c_link) {
  147.         if (p->c_onscreen != Nowhere)
  148.             p->c_onscreen -= growth;
  149.     }
  150. }
  151.  
  152.  
  153. /*
  154.  * Make room for possible insertions.
  155.  * (If a line is inserted, it may be necessary to delete lines
  156.  * further on the screen.)
  157.  */
  158.  
  159. Hidden Procedure
  160. makeroom(p, curlno, delcnt)
  161.     register cell *p;
  162.     register int curlno;
  163.     register int delcnt;
  164. {
  165.     register int here = 0;
  166.     register int need = Space(p);
  167.     register int amiss;
  168.     int avail;
  169.     int diff;
  170.  
  171.     Assert(p);
  172.     do {
  173.         p = p->c_link;
  174.         if (!p)
  175.             return delcnt;
  176.     } while (p->c_onscreen == Nowhere);
  177.     here = p->c_onscreen - delcnt;
  178.     avail = here - curlno;
  179.     amiss = need - avail;
  180. #ifndef NDEBUG
  181.     if (dflag)
  182.         debug("[makeroom: curlno=%d, delcnt=%d, here=%d, avail=%d, amiss=%d]",
  183.             curlno, delcnt, here, avail, amiss);
  184. #endif NDEBUG
  185.     if (amiss <= 0)
  186.         return delcnt;
  187.     if (amiss > delcnt) {
  188.         for (; p; p = p->c_link) {
  189.             if (p->c_onscreen != Nowhere) {
  190.                 diff = amiss-delcnt;
  191.                 if (p->c_onscreen - delcnt - here < diff)
  192.                     diff = p->c_onscreen - delcnt - here;
  193.                 if (diff > 0) {
  194.                     trmscrollup(here, winheight, diff);
  195.                     delcnt += diff;
  196.                 }
  197.                 p->c_onscreen += -delcnt + amiss;
  198.                 here = p->c_onscreen - amiss;
  199.                 if (p->c_onscreen >= winheight)
  200.                     p->c_onscreen = Nowhere;
  201.             }
  202.             here += Space(p);
  203.         }
  204.         /* Now for all p encountered whose p->c_onscreen != Nowhere,
  205.         /* p->c_onscreen - amiss is its actual position. */
  206.         if (amiss > delcnt) {
  207.             trmscrollup(winheight - amiss, winheight, amiss-delcnt);
  208.             delcnt = amiss;
  209.         }
  210.     }
  211.     /* Now amiss <= delcnt */
  212.     trmscrollup(curlno + avail, winheight, -amiss);
  213.     return delcnt - amiss;
  214. }
  215.  
  216.  
  217. /*
  218.  * Addition to makeroom - make sure the status line is not overwritten.
  219.  * Returns new delcnt, like makeroom does.
  220.  */
  221.  
  222. Hidden int
  223. make2room(p, curlno, delcnt)
  224.     cell *p;
  225.     int curlno;
  226.     int delcnt;
  227. {
  228.     int nextline = curlno + Space(p);
  229.     int sline = winheight - delcnt;
  230.     int diff;
  231.  
  232.     if (sline < curlno) {
  233. #ifndef NDEBUG
  234.         debug("[Status line overwritten]");
  235. #endif NDEBUG
  236.         return delcnt;
  237.     }
  238.     if (nextline > winheight)
  239.         nextline = winheight;
  240.     diff = nextline - sline;
  241.     if (diff > 0) {
  242.         trmscrollup(sline, winheight, -diff);
  243.         delcnt -= diff;
  244.     }
  245.     return delcnt;
  246.         
  247. }
  248.  
  249.  
  250. /*
  251.  * Routine called for every change in the screen.
  252.  */
  253.  
  254. Visible Procedure
  255. virtupdate(oldep, newep, highest)
  256.     environ *oldep;
  257.     environ *newep;
  258.     int highest;
  259. {
  260.     environ old;
  261.     environ new;
  262.     register int oldlno;
  263.     register int newlno;
  264.     register int oldlcnt;
  265.     register int newlcnt;
  266.     register int i;
  267.  
  268.     if (!oldep) {
  269.         highest = 1;
  270.         trmputdata(winstart, winheight, indent, "");
  271.         discard(tops);
  272.         tops = Cnil;
  273.         Ecopy(*newep, old);
  274.     }
  275.     else {
  276.         Ecopy(*oldep, old);
  277.     }
  278.     Ecopy(*newep, new);
  279.  
  280.     savefocus(&new);
  281.  
  282.     oldlcnt = fixlevels(&old, &new, highest);
  283.     newlcnt = -width(tree(new.focus));
  284.     if (newlcnt < 0)
  285.         newlcnt = 0;
  286.     i = -width(tree(old.focus));
  287.     if (i < 0)
  288.         i = 0;
  289.     newlcnt -= i - oldlcnt;
  290.         /* Offset newlcnt as much as oldcnt is offset */
  291.     
  292.     oldlno = Ycoord(old.focus);
  293.     newlno = Ycoord(new.focus);
  294.     if (!atlinestart(&old))
  295.         ++oldlcnt;
  296.     else
  297.         ++oldlno;
  298.     if (!atlinestart(&new))
  299.         ++newlcnt;
  300.     else
  301.         ++newlno;
  302.     Assert(oldlno == newlno);
  303.  
  304.     tops = replist(tops, build(new.focus, newlcnt), oldlno, oldlcnt);
  305.  
  306.     setfocus(tops); /* Incorporate the information saved by savefocus */
  307.  
  308.     Erelease(old);
  309.     Erelease(new);
  310. }
  311.  
  312.  
  313. Hidden bool
  314. atlinestart(ep)
  315.     environ *ep;
  316. {
  317.     register string repr = noderepr(tree(ep->focus))[0];
  318.  
  319.     return Fw_negative(repr);
  320. }
  321.  
  322.  
  323. /*
  324.  * Make the two levels the same, and make sure they both are line starters
  325.  * if at all possible.  Return the OLD number of lines to be replaced.
  326.  * (0 if the whole unit has no linefeeds.)
  327.  */
  328.  
  329. Hidden int
  330. fixlevels(oldep, newep, highest)
  331.     register environ *oldep;
  332.     register environ *newep;
  333.     register int highest;
  334. {
  335.     register int oldpl = pathlength(oldep->focus);
  336.     register int newpl = pathlength(newep->focus);
  337.     register bool intraline = No;
  338.     register int w;
  339.  
  340.     if (oldpl < highest)
  341.         highest = oldpl;
  342.     if (newpl < highest)
  343.         highest = newpl;
  344.     while (oldpl > highest) {
  345.         up(&oldep->focus) || Abort();
  346.         --oldpl;
  347.     }
  348.     while (newpl > highest) {
  349.         up(&newep->focus) || Abort();
  350.         --newpl;
  351.     }
  352.     if (Ycoord(newep->focus) != Ycoord(oldep->focus) ||
  353.         Level(newep->focus) != Level(newep->focus)) {
  354.         /* Inconsistency found.  */
  355.         Assert(highest > 1); /* Inconsistency at top level. Stop. */
  356.         return fixlevels(oldep, newep, 1); /* Try to recover. */
  357.     }
  358.     intraline = width(tree(oldep->focus)) >= 0
  359.         && width(tree(newep->focus)) >= 0;
  360.     while (!atlinestart(oldep) || !atlinestart(newep)) {
  361.         /* Find beginning of lines for both */
  362.         if (!up(&newep->focus)) {
  363.             Assert(!up(&newep->focus));
  364.             break;
  365.         }
  366.         --oldpl;
  367.         up(&oldep->focus) || Abort();
  368.         --newpl;
  369.     }
  370.     if (intraline)
  371.         return atlinestart(oldep);
  372.     w = width(tree(oldep->focus));
  373.     return w < 0 ? -w : 0;
  374. }
  375.  
  376.  
  377. /*
  378.  * Initialization code.
  379.  */
  380.  
  381. Visible Procedure
  382. initshow()
  383. {
  384.     int flags = 0;
  385. #ifndef NDEBUG
  386.     if (dflag)
  387.         fprintf(stderr, "*** initshow();\n\r");
  388. #endif NDEBUG
  389.     if (!trmstart(&winheight, &llength, &flags)) {
  390.         endunix();
  391.         exit(2);
  392.     }
  393.     noscroll = (flags&2) == 0;
  394.     nosense = (flags&8) == 0;
  395.     winstart = --winheight;
  396. }
  397.  
  398.  
  399. /*
  400.  * Routine to move the cursor to the first line after the just edited
  401.  * document.  (Called after each editing action.)
  402.  */
  403.  
  404. Visible Procedure
  405. endshow()
  406. {
  407.     register cell *p;
  408.     register int last = winheight;
  409.  
  410.     for (p = tops; p; p = p->c_link) {
  411.         if (p->c_onscreen != Nowhere)
  412.             last = p->c_onscreen + Oldspace(p);
  413.     }
  414.     if (last > winheight)
  415.         last = winheight;
  416.     discard(tops);
  417.     tops = Cnil;
  418.     trmputdata(last, winheight, 0, "");
  419.     trmsync(last, 0);
  420.     trmend();
  421. }
  422.  
  423.  
  424. /*
  425.  * Translate a cursor position in tree coordinates.
  426.  *
  427.  * ***** DOESN'T WORK IF SCREEN INDENT DIFFERS FROM TREE INDENT! *****
  428.  * (I.e. for lines with >= 80 spaces indentation)
  429.  */
  430.  
  431. Visible bool
  432. backtranslate(py, px)
  433.     int *py;
  434.     int *px;
  435. {
  436.     cell *p;
  437.     int y = *py;
  438.     int x = *px;
  439.     int i;
  440.  
  441.     for (i = 0, p = tops; p; ++i, p = p->c_link) {
  442.         if (p->c_onscreen != Nowhere
  443.             && y >= p->c_onscreen && y < p->c_onscreen + Space(p)) {
  444.             *px += (y - p->c_onscreen) * llength - indent;
  445.             if (*px < 0)
  446.                 *px = 0;
  447.             *py = i;
  448.             if (p->c_oldvhole && (y > focy || y == focy && x > focx))
  449.                 --*px; /* Correction if beyond Vhole on same logical line */
  450.             return Yes;
  451.         }
  452.     }
  453.     error(GOTO_OUT);
  454.     return No;
  455. }
  456.  
  457.  
  458. /*
  459.  * Set the indent level and window start line.
  460.  */
  461.  
  462. Visible Procedure
  463. setindent(x)
  464.     int x;
  465. {
  466.     winstart= winheight;
  467.     indent= x;
  468. }
  469.  
  470.  
  471. /*
  472.  * Show the command prompt.
  473.  */
  474.  
  475. Visible Procedure cmdprompt(prompt)
  476.     string prompt;
  477. {
  478.     setindent(strlen(prompt));
  479.     trmputdata(winstart, winstart, 0, prompt);
  480. }
  481.